﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Core.Entities;
using Core.Reader;
using Core.Tools;
using System.Text.RegularExpressions;
using System.IO;
using System.Reflection;
using Core.Writer;
using Core.ReadWriter;
using Core.Enums;
using Microsoft.CSharp;
using System.CodeDom.Compiler;
using Core.Exceptions;
using System.Reflection.Emit;

namespace Core.CommandProcesser
{
    public class CSharpProcesser : BaseCommandProcesser
    {
        private const string CodeTemp = "{0} public class CSharpCommand : ISystemCommand { public string Name { get { return \"{1}\"; } } public void Process(BaseProcess Process, CommandInfo CommandInfo, IDataWriter Writer) {\n {2} \n} }";

        public static Assembly Build(CommandInfo CommandInfo)
        {
            var ImportsList = new List<string>();
            var UsingsList = new List<string>();
            var ValidationsList = new List<CommandFieldVerifier>();

            foreach (var Item in AppDomain.CurrentDomain.GetAssemblies())
            {
                if (Item.IsDynamic)
                {
                    continue;
                }

                ImportsList.Add(Item.Location);
            }

            ImportsList.Add("System.Runtime.dll");

            UsingsList.Add("Core");
            UsingsList.Add("Core.CommandProcesser");
            UsingsList.Add("Core.Entities");
            UsingsList.Add("Core.Enums");
            UsingsList.Add("Core.Exceptions");
            UsingsList.Add("Core.Formats");
            UsingsList.Add("Core.Reader");
            UsingsList.Add("Core.Service");
            UsingsList.Add("Core.Structs");
            UsingsList.Add("Core.Tools");
            UsingsList.Add("Core.Writer");

            UsingsList.Add("System");
            UsingsList.Add("System.Collections.Generic");
            UsingsList.Add("System.Linq");
            UsingsList.Add("System.Text");
            UsingsList.Add("System.Threading.Tasks");

            string TempCode = CommandInfo.Code;

            GetValidations(ref TempCode, ImportsList, UsingsList, ValidationsList);
            
            var UsingsBuilder = new StringBuilder();

            foreach (var Item in UsingsList)
            {
                UsingsBuilder.Append("using ");
                UsingsBuilder.Append(Item);
                UsingsBuilder.Append(";");
            }

            var Code = StringHelper.Format(CodeTemp, UsingsBuilder.ToString(), CommandInfo.Name, TempCode);

            CommandInfo.InternalValidations = ValidationsList.ToArray();

            using (CSharpCodeProvider Provider = new CSharpCodeProvider())
            {
                CompilerParameters Params = new CompilerParameters();

                foreach (var Item in ImportsList)
                {
                    Params.ReferencedAssemblies.Add(Item);
                }

                Params.GenerateExecutable = false;
                Params.GenerateInMemory = true;
                Params.IncludeDebugInformation = false;

                CompilerResults Result = Provider.CompileAssemblyFromSource(Params, Code);

                if (Result.Errors != null && Result.Errors.Count != 0)
                {
                    StringBuilder Errors = new StringBuilder();

                    Errors.AppendLine("编译出错 -- ");

                    var CompilerErrors = new List<CompilerError>();

                    foreach (CompilerError Item in Result.Errors)
                    {
                        if (Item.IsWarning)
                        {
                            continue;
                        }

                        Errors.AppendLine("\t第 " + Item.Line + " 行，第 " + Item.Column + " 列，错误号：" + Item.ErrorNumber + "，错误信息：" + Item.ErrorText + "。");

                        CompilerErrors.Add(Item);
                    }

                    if (CompilerErrors.Count != 0)
                    {
                        throw new CompilerException(Errors.ToString(), CompilerErrors);
                    }
                }

                return Result.CompiledAssembly;
            }
        }

        public override void Initialization(CommandInfo CommandInfo)
        {
            var Assembly = Build(CommandInfo);

            var Type = Assembly.GetType("CSharpCommand");

            var CSharpCommand = (ISystemCommand)Type.GetConstructor(Type.EmptyTypes).Invoke(null);

            CommandInfo.InternalTag = CSharpCommand;
        }

        public override void Process(BaseProcess Process, CommandInfo CommandInfo, Action<IDataReader> Callback)
        {
            var CSharpCommand = CommandInfo.InternalTag as ISystemCommand;

            if (CSharpCommand == null)
            {
                throw new Exception(CommandInfo.Name + " -- 该命令没有实现！");
            }

            var TableContent = new Table();

            TableContent.Next();

            using (var ReadWriter = new TableReadWriter(TableContent))
            {
                if ((CommandInfo.Sign & CommandSigns.SingleObjectResult) != 0)
                {
                    ReadWriter.ObjectType = RWTypes.Object;
                }
                else
                {
                    ReadWriter.ObjectType = RWTypes.Table;
                }

                CSharpCommand.Process(Process, CommandInfo, ReadWriter);

                Callback(ReadWriter);
            }
        }

        public override void Process(BaseProcess Process, CommandInfo CommandInfo, IDataWriter Writer)
        {
            var CSharpCommand = CommandInfo.InternalTag as ISystemCommand;

            if (CSharpCommand == null)
            {
                throw new Exception(CommandInfo.Name + " -- 该命令没有实现！");
            }

            Writer.Next();

            CSharpCommand.Process(Process, CommandInfo, Writer);
        }
    }
}